package info.niwota.frames;

import android.graphics.Bitmap;

// This is a cache for Bitmap displayed in PhotoFrameActivity (normal mode, thumb only).
public class BitmapCache implements ImageViewTouchBase.Recycler {

	public static class Entry {
		int mPos;
		Bitmap mBitmap;

		public Entry() {
			clear();
		}

		public void clear() {
			mPos = -1;
			mBitmap = null;
		}
	}

	private final Entry[] mCache;

	public BitmapCache(int size) {
		mCache = new Entry[size];
		for (int i = 0; i < mCache.length; i++) {
			mCache[i] = new Entry();
		}
	}

	// Given the position, find the associated entry. Returns null if there is
	// no such entry.
	private Entry findEntry(int pos) {
		for (Entry e : mCache) {
			if (pos == e.mPos) {
				return e;
			}
		}
		return null;
	}

	// Returns the thumb bitmap if we have it, otherwise return null.
	public synchronized Bitmap getBitmap(int pos) {
		Entry e = findEntry(pos);
		if (e != null) {
			return e.mBitmap;
		}
		return null;
	}

	public synchronized void put(int pos, Bitmap bitmap) {
		// First see if we already have this entry.
		if (findEntry(pos) != null) {
			return;
		}

		// Find the best entry we should replace.
		// See if there is any empty entry.
		// Otherwise assuming sequential access, kick out the entry with the
		// greatest distance.
		Entry best = null;
		int maxDist = -1;
		for (Entry e : mCache) {
			if (e.mPos == -1) {
				best = e;
				break;
			} else {
				int dist = Math.abs(pos - e.mPos);
				if (dist > maxDist) {
					maxDist = dist;
					best = e;
				}
			}
		}

		// Recycle the image being kicked out.
		// This only works because our current usage is sequential, so we
		// do not happen to recycle the image being displayed.
		if (best.mBitmap != null) {
			best.mBitmap.recycle();
		}

		best.mPos = pos;
		best.mBitmap = bitmap;
	}

	// Recycle all bitmaps in the cache and clear the cache.
	public synchronized void clear() {
		for (Entry e : mCache) {
			if (e.mBitmap != null) {
				e.mBitmap.recycle();
			}
			e.clear();
		}
	}

	// Returns whether the bitmap is in the cache.
	public synchronized boolean hasBitmap(int pos) {
		Entry e = findEntry(pos);
		return (e != null);
	}

	// Recycle the bitmap if it's not in the cache.
	// The input must be non-null.
	public synchronized void recycle(Bitmap b) {
		for (Entry e : mCache) {
			if (e.mPos != -1) {
				if (e.mBitmap == b) {
					return;
				}
			}
		}
		b.recycle();
	}

}
